import machine
import ustruct as struct
from tft import st7789py as st
from tft import tft_config


class DisplayManager:
    """
    管理 TFT 显示屏的类。
    """

    def __init__(self, tft):
        """
        初始化 DisplayManager 类。
        """
        self.tft = tft

    def read_bmp_header(self, file):
        """
        读取 BMP 文件头信息。

        Args:
            file (file): 打开的 BMP 文件对象。

        Returns:
            tuple: 包含偏移量、宽度、高度和深度的元组。
        """
        try:
            # 检查文件是否为BMP格式
            if file.read(2) != b'BM':
                raise ValueError("Not a BMP file")
            file.read(8)  # 文件大小(4), 创建者字节(4)
            offset = struct.unpack('<I', file.read(4))[0]
            file.read(4)  # DIB 头大小
            width = struct.unpack('<I', file.read(4))[0]
            height = struct.unpack('<i', file.read(4))[0]
            # 确保平面数为1，这是BMP格式的要求
            if struct.unpack('<H', file.read(2))[0] != 1:
                raise ValueError("Planes must be 1")
            depth = struct.unpack('<H', file.read(2))[0]
            # 确保BMP格式为24位且未压缩
            if depth != 24 or struct.unpack('<I', file.read(4))[0] != 0:
                raise ValueError("Unsupported BMP format")
            return offset, width, height, depth
        except Exception as e:
            print(f"Error reading BMP header: {e}")
            raise

    def display_bmp(self, file_path, x, y):
        """
        在 TFT 显示屏上显示 BMP 图像。

        Args:
            file_path (str): BMP 文件的路径。
            x (int): 图像显示的起始 x 坐标。
            y (int): 图像显示的起始 y 坐标。
        """
        try:
            with open(file_path, 'rb') as f:
                offset, width, height, _ = self.read_bmp_header(f)
                print("Image size:", width, "x", height)

                rowsize = (width * 3 + 3) & ~3
                flip = height > 0
                height = abs(height)

                w, h = width, height
                self.tft._set_window(x, y, x + w - 1, y + h - 1)

                buffer = bytearray(rowsize)
                pixels = bytearray(w * 2)

                for row in range(h):
                    pos = offset + (height - 1 - row if flip else row) * rowsize
                    f.seek(pos)
                    f.readinto(buffer)

                    for col in range(w):
                        bgr = buffer[col * 3:col * 3 + 3]
                        color = st.color565(bgr[2], bgr[1], bgr[0])
                        pixels[col * 2:(col * 2 + 2)] = struct.pack('>H', color)

                    self.tft.blit_buffer(pixels, x, y + row, w, 1)
        except Exception as e:
            print(f"Error displaying BMP image: {e}")

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.tft.spi.deinit()

    def __del__(self):
        self.tft.spi.deinit()


def main():
    """
    主函数，初始化 DisplayManager 并显示 BMP 图像。
    """
    try:
        with tft_config.config(0) as tft:
            with DisplayManager(tft) as dm:
                dm.display_bmp('test128x160.bmp', 20, 20)
                tft.display_bmp('test128x160.bmp', 50, 100)
                tft.text(32, "加载BMP图片", 20, 200, st.WHITE, st.RED)
    except Exception as e:
        print(f"Error in main function: {e}")


if __name__ == "__main__":
    main()
